/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ejb.controlador.websocket;

import java.awt.Image;
import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.imageio.ImageIO;
import javax.inject.Named;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.ejb.endpointwebsocket.util.SigEscenario;
import org.ejb.modelo.Evento;
import org.ejb.modelo.Juego;
import org.ejb.modelo.Nivel;
import org.ejb.modelo.Nivel.TipoNivel;
import org.ejb.negocio.JuegosFacade;
import org.ejb.persistencia.Binjuego;
import org.ejb.persistencia.Juegos;
import org.ejb.persistencia.Xmljuego;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author MoisesAntonio
 */
@Named("jugarController")
@SessionScoped
public class JugarController implements Serializable {

    //Variables del juego.

    private Juego juego;
    private ArrayList<Rectangle> eventos;
    private int[] idNiveles;
    private Nivel nivel;

    //Variables de la bbdd.
    private Juegos juegoCargado;
    private int id;

    @EJB
    private JuegosFacade ejbJuego;

    public JugarController() {
    }

    /**
     * *************************************************************************
     * En esta primera parte, voy a crear aquellos métodos que sirvan para
     * cargar el juego desde la base de datos a los objetos correspondientes
     * (Juego, Nivel y Evento). De esta forma el controlador podrá preparar lo
     * necesario para el usuario.
     *************************************************************************
     */
    /**
     * Indica que id de juego es.
     *
     * @param id Identificador del juego.
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * Obtiene el identificador del juego.
     *
     * @return Id del juego.
     */
    public int getId() {
        return id;
    }
    
    public void setJuegoCargado(Juegos j){
        juegoCargado=j;
    }
    
    public Juegos getJuegoCargado(){
        return juegoCargado;
    }
    
    public String getNombre(){
        return juegoCargado.getNombreJuego();
    }

    /**
     * Carga de la base de datos el juego.
     *
     * @param id
     */
    public void cargarJuego(int id) {
        this.id=id;
        juegoCargado = ejbJuego.find(id);
        if (juegoCargado != null) {
            parsearJuego();
            if(juego!=null){
                nivel = juego.iniciar(); //Esto inicia el juego.
                eventos= new ArrayList<>();
            }else{
                //Error
            }
        } else {
            //MostrarError
        }
    }

    private void parsearJuego() {
        Xmljuego xml = juegoCargado.getXmljuegoList().get(0);
        List<Binjuego> bin = juegoCargado.getBinjuegoList();

        //Tengo que pasear los datos en binario a XML:
        try {
            //Cargo el xml info en un InputStream para ser leido por el parseador XML
            InputStream fis = new ByteArrayInputStream(xml.getInfo());

            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(fis);

            doc.getDocumentElement().normalize();	//Se debe normalizar el XML

            //Cargamos el objeto juego.
            juego = new Juego(doc.getElementsByTagName("name").item(0).getTextContent());	//Leo el nombre del juego.
            juego.setDescp(doc.getElementsByTagName("desc").item(0).getTextContent()); //Leo la descripción del juego.
            juego.setTipo(juegoCargado.getTipo());
            juego.setId(juegoCargado.getIdJuego());
            juego.setEdad(juegoCargado.getEdad());

            //Cargamos los niveles xml juego:
            fis = new ByteArrayInputStream(xml.getJuego()); //Cargamos el juego.

            dbFactory = DocumentBuilderFactory.newInstance();
            dBuilder = dbFactory.newDocumentBuilder();
            doc = dBuilder.parse(fis);
            doc.getDocumentElement().normalize();

            //Esto cargará cada uno de los niveles
            NodeList nList = doc.getElementsByTagName("level");

            for (int i = 0; i < nList.getLength(); i++) {
                Element eElement = (Element) nList.item(i);
                Nivel n = juego.nuevoNivel();	//Creamos un nivel.
                n.setNombre(eElement.getAttribute("name"));
                n.setNumero(Integer.parseInt(eElement.getAttribute("id")));

                for (Binjuego bin1 : bin) {
                    //Recorremos todas las imágenes en busca de la que tenga
                    if (bin1.getBinjuegoPK().getIdBin() == n.getNumero()) {
                        fis = new ByteArrayInputStream(bin1.getBindata());
                        Image image = ImageIO.read(fis);
                        n.setEscenario(image);
                    }
                }

                n.setTipo(TipoNivel.valueOf(eElement.getAttribute("type")));

                if (Integer.parseInt(eElement.getAttribute("music")) == 1) {
                    //Cargamos el sonido.
                }

                NodeList lEven = eElement.getChildNodes();

                for (int k = 0; k < lEven.getLength(); k++) {
                    Element eve = (Element) lEven.item(k);
                    int a = Integer.parseInt(eve.getAttribute("posx"));
                    int b = Integer.parseInt(eve.getAttribute("posy"));
                    int c = Integer.parseInt(eve.getAttribute("width"));
                    int d = Integer.parseInt(eve.getAttribute("height"));
                    int l = Integer.parseInt(eve.getAttribute("level"));
                    Evento e = new Evento(a, b, c, d);
                    e.setConexion(l);
                    n.anadirEvento(e);

                }

            }

        } catch (ParserConfigurationException | SAXException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * *************************************************************************
     * En esta parte de aquí abajo, llevaremos el control del juego.
     ***************************************************************************
     */
    
    /**
     * Este método calcula si se ha hecho click en uno de los eventos, 
     * en caso de que así sea, carga el siguiente nivel.
     * @param x Posición x relativa (lo calcula el scrip AJAX)
     * @param y Posición y relativa (lo calcula el scrip AJAX)
     * @return Valor booleano indicando si ha habido impacto.
     */
    public boolean ejecutarEventos(int x, int y) {
        for (int i = 0; i < eventos.size(); i++) {
            if (eventos.get(i).contains(x, y)) {
                //reproducirSonidos(i);
                nivel = juego.siguienteNivel(idNiveles[i]);
                //cargarNivel();
                return true;
            }
        }
        return false;
    }

    public SigEscenario cargarNivel() {

        cargarEventos();
        //panel2.setNivel(nivel);   Estos métodos representan como se carga el nivel en la app Java
        //panel2.repaint();         Debo cargarlos en el WebSocket.
        SigEscenario siguiente = new SigEscenario(nivel.getNumero());
        siguiente.setI(nivel.getEscenario());
        
        return siguiente;
    }

    /**
     * Los eventos cargados tienen una posición y un ancho relativo, es decir,
     * las posiciones están representadas en tanto por mil.
     */
    private void cargarEventos() {
        eventos.clear();
        idNiveles = new int[nivel.numEventos()];
        for (int i = 0; i < nivel.numEventos(); i++) {
            Evento e = nivel.getEvento(i);
            Rectangle r = new Rectangle(e.getX(), e.getY() , e.getAncho() , e.getAlto());
            eventos.add(r);
            idNiveles[i] = e.getConexion();
        }
    }

}
